package io.kiki.sba.registry.store.jdbc.version.config;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class BaseConfigRepository<T extends ConfigEntry> {
    private static final Logger logger = LoggerFactory.getLogger(BaseConfigRepository.class);

    private final String name;


    public BaseConfigRepository(String name) {
        this.name = name;

    }

    public boolean put(T entry) {
        if (entry == null) {
            logger.error("name: {} update config entry is null.", name);
            return false;
        }

        try {
            T exist = queryExistVersion(entry);
            if (exist == null) {
                // it will throw duplicate key exception when parallel invocation
                insert(entry);
                return true;
            }
            return put(entry, exist.getDataVersion());
        } catch (Throwable t) {
            logger.error("name: {} update config entry:{} error.", name, entry, t);
            return false;
        }
    }

    public boolean put(T entry, long expectVersion) {
        if (entry == null) {
            logger.error("name: {} update config entry is null.", name);
            return false;
        }
        try {
            if (entry.getDataVersion() <= expectVersion) {
                logger.error("update config entry fail, update.version:{} <= expectVersion:{}", entry.getDataVersion(), expectVersion);
                return false;
            }

            if (expectVersion == 0) {
                // it will throw duplicate key exception when parallel invocation
                insert(entry);
                logger.info("insert entry:{} success.", entry);
                return true;
            }

            int affect = updateWithExpectVersion(entry, expectVersion);
            if (affect == 0) {
                logger.error("update config entry fail, affect=0, expectVersion={}, entry:{}", expectVersion, entry);
                return false;
            }
            logger.info("update entry:{}, expectVersion:{} success.", entry, expectVersion);
            return true;
        } catch (Throwable t) {
            logger.error("name: {} update config entry:{} error.", name, entry, t);
            return false;
        }
    }

    protected abstract T queryExistVersion(T entry);

    protected abstract long insert(T entry);

    protected abstract int updateWithExpectVersion(T entry, long exist);
}
